import bpy
from bpy.types import Operator, UIList, Panel
from bpy.props import IntProperty, StringProperty, CollectionProperty, BoolProperty

def create_face_change_node_group(name, expression_count, uv_map_names):
    # 创建新的着色器节点组
    node_group = bpy.data.node_groups.new(name, 'ShaderNodeTree')
    
    # 创建Group Input节点
    group_inputs = node_group.nodes.new('NodeGroupInput')
    group_inputs.location = (-800, 0)
    
    # 创建Group Output节点
    group_outputs = node_group.nodes.new('NodeGroupOutput')
    group_outputs.location = (800, 0)
    
    # 添加选择值输入插座
    select_socket = node_group.interface.new_socket(
        name="Select",
        in_out='INPUT',
        socket_type='NodeSocketInt',
    )
    # 设置选择值的最小最大值
    select_socket.min_value = 1
    select_socket.max_value = expression_count
    select_socket.default_value = 1
    
    sub_node = node_group.nodes.new('ShaderNodeMath')
    sub_node.location = (-400, 200)
    sub_node.operation = 'SUBTRACT'
    sub_node.inputs[1].default_value = 1
    
    node_group.links.new(group_inputs.outputs["Select"], sub_node.inputs[0])
    
    # 添加输出插座
    node_group.interface.new_socket(
        name="Output",
        in_out='OUTPUT',
        socket_type='NodeSocketColor'
    )
    
    # 创建混合节点链
    previous_mix = None
    for i in range(expression_count-1):
        # 创建比较节点
        compare_node = node_group.nodes.new('ShaderNodeMath')
        compare_node.location = (-200, -i * 200)
        compare_node.operation = 'COMPARE'
        compare_node.inputs[1].default_value = i + 1  # 比较值从1开始
        
        # 连接选择值到比较节点
        node_group.links.new(sub_node.outputs[0], compare_node.inputs[0])
        
        # 创建混合节点
        mix_node = node_group.nodes.new('ShaderNodeMixRGB')
        mix_node.location = (200, -i * 200)
        mix_node.blend_type = 'MIX'
        mix_node.inputs[0].default_value = 0.0  # 默认不混合
        
        # 连接比较结果到混合系数
        node_group.links.new(compare_node.outputs[0], mix_node.inputs[0])
        if i == 0:
            if len(uv_map_names) > 0:
                # 第一个混合节点连接前两个表达式
                UVnode1 = node_group.nodes.new('ShaderNodeUVMap')
                UVnode1.location = (-500,  0)
                UVnode1.name = 'E_1'
                UVnode1.uv_map = uv_map_names[0]
                node_group.links.new(UVnode1.outputs[0], mix_node.inputs[1])
            else:
                # 如果只有一个UV贴图，连接默认颜色
                input_socket1 = node_group.interface.new_socket(
                    name=f"E_1",
                    in_out='INPUT',
                    socket_type='NodeSocketColor'
                )
                node_group.links.new(group_inputs.outputs["E_1"], mix_node.inputs[1])
            if len(uv_map_names) > 1:
                UVnode2 = node_group.nodes.new('ShaderNodeUVMap')
                UVnode2.location = (-500,  -200)
                UVnode2.name = 'E_2'
                UVnode2.uv_map = uv_map_names[1]
                node_group.links.new(UVnode2.outputs[0], mix_node.inputs[2])
            else:
                # 如果只有一个UV贴图，连接默认颜色
                input_socket2 = node_group.interface.new_socket(
                    name=f"E_2",
                    in_out='INPUT',
                    socket_type='NodeSocketColor'
                )
                node_group.links.new(group_inputs.outputs["E_2"], mix_node.inputs[2])
        else:
            # 后续混合节点连接前一个混合结果和下一个表达式
            if len(uv_map_names) > i+1:
                node_group.links.new(previous_mix.outputs[0], mix_node.inputs[1])
                UVnode = node_group.nodes.new('ShaderNodeUVMap')
                UVnode.location = (-500,  -200*(i+1))
                UVnode.name = f'E_{i+2}'
                UVnode.uv_map = uv_map_names[i+1]
                node_group.links.new(UVnode.outputs[0], mix_node.inputs[2])
            else:
                node_group.links.new(previous_mix.outputs[0], mix_node.inputs[1])
                node_group.links.new(group_inputs.outputs[f"E_{i+2}"], mix_node.inputs[2])
        previous_mix = mix_node

        # 连接最后一个混合节点
        node_group.links.new(previous_mix.outputs[0], group_outputs.inputs["Output"])
    
    # 存储表情数量到节点组自定义属性
    node_group["expression_count"] = expression_count
    
    return node_group

# 获取可用的UV贴图列表
def get_available_uv_maps(context):
    """获取当前对象的可用UV贴图列表"""
    uv_maps = []
    if context and context.object and context.object.type == 'MESH':
        for uv_layer in context.object.data.uv_layers:
            uv_maps.append(uv_layer.name)
    return uv_maps

# 获取选中物体中使用指定节点组的节点
def get_selected_nodes_with_group(context, group_name):
    """获取选中物体中使用指定节点组的节点列表"""
    selected_nodes = []
    
    # 获取所有选中物体
    selected_objects = [obj for obj in context.selected_objects if obj.type == 'MESH']
    
    for obj in selected_objects:
        # 检查对象的材质
        for material_slot in obj.material_slots:
            if material_slot.material and material_slot.material.use_nodes:
                material = material_slot.material
                # 查找使用指定节点组的节点
                for node in material.node_tree.nodes:
                    if (node.type == 'GROUP' and node.node_tree and 
                        node.node_tree.name == group_name and
                        'Select' in node.inputs):
                        selected_nodes.append((node, obj))
    
    return selected_nodes

# 获取所有使用指定节点组的节点
def get_all_nodes_with_group(group_name):
    """获取所有使用指定节点组的节点列表"""
    all_nodes = []
    
    for material in bpy.data.materials:
        if material.use_nodes and material.node_tree:
            for node in material.node_tree.nodes:
                if (node.type == 'GROUP' and node.node_tree and 
                    node.node_tree.name == group_name and
                    'Select' in node.inputs):
                    all_nodes.append(node)
    
    return all_nodes

# UV贴图列表项属性
class UVMapItem(bpy.types.PropertyGroup):
    """用于存储UV贴图列表项的属性组"""
    name: StringProperty(name="UV贴图名称")# type: ignore
    enabled: BoolProperty(name="启用", 
                        default=True,
                        )# type: ignore

# 节点组列表项属性
class NodeGroupItem(bpy.types.PropertyGroup):
    """用于存储节点组列表项的属性组"""
    name: StringProperty(name="节点组名称")# type: ignore
    expression_count: IntProperty(name="表情数量", default=2)# type: ignore
    node_tree_name: StringProperty(name="节点树名称")# type: ignore
    # is_used: BoolProperty(name="是否被使用", default=False)# type: ignore

# UV贴图列表UI
class NODE_UL_UV_MAPS(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.prop(item, "enabled", text=item.name)
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.prop(item, "enabled", text=item.name)

# 节点组列表UI
class NODE_UL_NODE_GROUPS(UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            # 显示节点组名称和勾选标识
            scene = context.scene
            is_active = scene.global_node_group_settings.active_node_group == item.name
            
            row = layout.row(align=True)
            
            is_used =False
            for met in bpy.data.materials:
                if met.node_tree.nodes.get(item.name):
                    is_used = True
            
            # 根据是否被使用显示不同的图标和颜色
            if is_used:
                row.label(text="", icon='NODETREE')
                row.label(text=item.name)
            else:
                row.label(text="", icon='ERROR')
                row = row.row(align=True)
                row.enabled = False  # 禁用未使用的节点组
                row.label(text=item.name)
            
            # 显示勾选图标（仅当是活动项时）
            if is_active:
                row.label(text="", icon='CHECKMARK')
        elif self.layout_type in {'GRID'}:
            layout.alignment = 'CENTER'
            layout.label(text=item.name)

class NODE_OT_REFRESH_UV_MAPS(Operator):
    """刷新UV贴图列表"""
    bl_idname = "node.refresh_uv_maps"
    bl_label = "刷新UV贴图"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        obj = context.object
        
        # 清除现有列表
        scene.face_change_uv_maps.clear()
        
        # 添加当前对象的UV贴图
        if obj and obj.type == 'MESH':
            for uv_layer in obj.data.uv_layers:
                item = scene.face_change_uv_maps.add()
                item.name = uv_layer.name
                item.enabled = False
        
        return {'FINISHED'}

class NODE_OT_REFRESH_NODE_GROUPS(Operator):
    """刷新节点组列表"""
    bl_idname = "node.refresh_node_groups"
    bl_label = "刷新节点组"
    bl_options = {'REGISTER', 'UNDO'}

    def execute(self, context):
        scene = context.scene
        
        # 清除现有列表
        scene.face_change_node_groups.clear()
        
        # 添加所有面部切换节点组
        for node_group in bpy.data.node_groups:
            if "expression_count" in node_group:
                item = scene.face_change_node_groups.add()
                item.name = node_group.name
                item.expression_count = node_group["expression_count"]
                item.node_tree_name = node_group.name
        return {'FINISHED'}

class NODE_OT_CREATE_FACE_CHANGE_GROUP(Operator):
    bl_idname = "node.create_face_change_group"
    bl_label = "创建节点群组"
    bl_description = "创建一个用于表情切换的节点组"
    bl_options = {'REGISTER', 'UNDO'}
    
    group_name: StringProperty(
        name="节点组名称",
        description="创建的节点组名称",
        default="E_G",
    ) # type: ignore
    
    expression_count: IntProperty(
        name="表情数量",
        description="需要切换的表情数量",
        default=2,
        min=2,
        max=500
    )# type: ignore

    def execute(self, context):
        scene = context.scene
        
        # 获取启用的UV贴图
        enabled_uv_maps = [item.name for item in scene.face_change_uv_maps if item.enabled]
        if len(enabled_uv_maps) >500:
            self.report({'ERROR'}, "启用的UV贴图数量不能超过500个")
            return {'CANCELLED'}
        
        # 创建节点组
        node_group = create_face_change_node_group(self.group_name, self.expression_count, enabled_uv_maps)
        self.group_name="E_G"
        # 存储所有选择的UV贴图到节点组中
        node_group["selected_uv_maps"] = enabled_uv_maps
        
        # 刷新节点组列表
        bpy.ops.node.refresh_node_groups()
        
        # 自动设置为活动节点组
        scene.global_node_group_settings.active_node_group = self.group_name
        
        self.report({'INFO'}, f"已创建表情切换节点组: {self.group_name}")
        return {'FINISHED'}
    
    def invoke(self, context, event):
        return context.window_manager.invoke_props_dialog(self, width=400)
    
    def draw(self, context):
        scene = context.scene
        layout = self.layout
        self.index = 0
        # 检查是否已存在同名的节点组
        while self.group_name in bpy.data.node_groups:
            print(f"节点组 {self.group_name} 已存在，尝试使用新的名称")
            self.group_name = f"E_G_{self.index}"
            self.index+=1
        layout.prop(self, "group_name")
        layout.prop(self, "expression_count")
        
        # 添加UV贴图列表
        if context.object and context.object.type == 'MESH':
            row = layout.row()
            row.operator("node.refresh_uv_maps", icon='FILE_REFRESH')
            
            if context.object.data.uv_layers:
                box = layout.box()
                box.label(text="选择要使用的UV贴图:")
                
                row = box.row()
                row.template_list(
                    "NODE_UL_UV_MAPS", 
                    "UV Maps", 
                    scene, 
                    "face_change_uv_maps", 
                    scene, 
                    "face_change_active_uv_map_index",
                    rows=4
                )
                
                # 显示提示信息
                enabled_count = len([item for item in scene.face_change_uv_maps if item.enabled])
                if enabled_count > self.expression_count:
                    self.expression_count = enabled_count
                box.label(text=f"已选择 {enabled_count}/{self.expression_count}个UV贴图", icon='INFO')
            else:
                layout.label(text="该网格没有UV贴图", icon='ERROR')
        else:
            layout.label(text="请先选择一个网格对象", icon='ERROR')

# 全局节点组控制属性组
class GlobalNodeGroupSettings(bpy.types.PropertyGroup):
    expression_index: IntProperty(
        name="表情索引",
        description="选中使用该群组的网格物体才可用",
        default=1,
        min=1,
        max=500,
        update=lambda self, context: update_expression_index(self, context)
    ) # type: ignore
    
    active_node_group: StringProperty(
        name="活动节点组",
        description="当前活动的节点组名称",
        default="",
        update=lambda self, context: update_active_node_group(self, context)
    ) # type: ignore

# 更新活动节点组的函数
def update_active_node_group(self, context):
    """当活动节点组改变时更新表情索引值"""
    scene = context.scene
    
    # 查找节点组
    node_group = bpy.data.node_groups.get(self.active_node_group)
    if not node_group:
        return
        
    # 获取节点组的表情数量
    expression_count = node_group.get("expression_count", 2)
    
    # 确保索引在有效范围内
    if self.expression_index > expression_count:
        self.expression_index = expression_count
    elif self.expression_index < 1:
        self.expression_index = 1
    
    # 选中所有使用该节点组的物体和节点
    select_objects_and_nodes_with_group(context, self.active_node_group)
    
    # 更新面板索引为活动物体的节点值
    update_panel_from_active_object(context, self.active_node_group)

# 更新表达式索引的函数
def update_expression_index(self, context):
    scene = context.scene
    active_node_group = self.active_node_group
    
    # 查找节点组
    node_group = bpy.data.node_groups.get(active_node_group)
    if not node_group:
        return
        
    # 获取节点组的表情数量
    expression_count = node_group.get("expression_count", 2)
    
    # 确保索引在有效范围内
    if self.expression_index > expression_count:
        self.expression_index = expression_count
    elif self.expression_index < 1:
        self.expression_index = 1
    
    # 只更新选中物体中使用该节点组的节点
    update_selected_nodes_with_group(context, active_node_group, self.expression_index)

# 选中所有使用指定节点组的物体和节点
def select_objects_and_nodes_with_group(context, group_name):
    """选中所有使用指定节点组的物体和节点"""
    # 清除当前选中状态
    for obj in context.view_layer.objects:
        obj.select_set(False)
    
    # 清除所有材质节点的选中状态
    for material in bpy.data.materials:
        if material.use_nodes and material.node_tree:
            for node in material.node_tree.nodes:
                node.select = False
    
    # 选中所有使用指定节点组的物体和节点
    objects_found = set()
    nodes_found = []
    
    for obj in bpy.data.objects:
        if obj.type != 'MESH':
            continue
            
        # 检查对象是否使用包含该节点组的材质
        for material_slot in obj.material_slots:
            if not material_slot.material or not material_slot.material.use_nodes:
                continue
                
            material = material_slot.material
            
            for node in material.node_tree.nodes:
                if (node.type == 'GROUP' and node.node_tree and 
                    node.node_tree.name == group_name):
                    
                    objects_found.add(obj)
                    obj.select_set(True)
                    
                    # 选中节点
                    node.select = True
                    nodes_found.append(node)
                    break
    
    # 设置活动物体
    if objects_found:
        # 设置第一个物体为活动物体
        first_obj = next(iter(objects_found))
        context.view_layer.objects.active = first_obj
        
        # 如果找到了节点，尝试切换到节点编辑器并选中节点
        if nodes_found and context.area and context.area.type == 'NODE_EDITOR':
            # 确保节点编辑器显示正确的材质
            for material_slot in first_obj.material_slots:
                if material_slot.material and material_slot.material.use_nodes:
                    context.space_data.node_tree = material_slot.material.node_tree
                    break
    
    return bool(objects_found)

# 更新选中物体中使用指定节点组的节点
def update_selected_nodes_with_group(context, group_name, expression_index):
    """更新选中物体中使用指定节点组的节点"""
    selected_nodes = get_selected_nodes_with_group(context, group_name)
    
    for node, obj in selected_nodes:
        if 'Select' in node.inputs:
            node.inputs['Select'].default_value = expression_index

# 从活动物体更新面板索引
def update_panel_from_active_object(context, group_name):
    """从活动物体更新面板索引"""
    scene = context.scene
    active_obj = context.view_layer.objects.active
    
    if not active_obj or active_obj.type != 'MESH':
        return
        
    # 检查活动物体的材质
    for material_slot in active_obj.material_slots:
        if not material_slot.material or not material_slot.material.use_nodes:
            continue
            
        material = material_slot.material
        
        # 查找使用指定节点组的节点
        for node in material.node_tree.nodes:
            if (node.type == 'GROUP' and node.node_tree and 
                node.node_tree.name == group_name and
                'Select' in node.inputs):
                
                # 更新面板索引为节点的值
                scene.global_node_group_settings.expression_index = node.inputs['Select'].default_value
                return

# 添加处理节点组输入值变化的处理函数
def update_node_group_inputs(scene):
    """更新所有材质中节点组的输入值"""
    try:
        active_node_group = scene.global_node_group_settings.active_node_group
        expression_index = scene.global_node_group_settings.expression_index
        
        if not active_node_group:
            return
            
        # 只检查活动物体中的节点值
        context = bpy.context
        active_obj = context.view_layer.objects.active
        
        if not active_obj or active_obj.type != 'MESH':
            return
        
        # 检查活动物体的材质
        for material_slot in active_obj.material_slots:
            if not material_slot.material or not material_slot.material.use_nodes:
                continue
                
            material = material_slot.material
            
            # 查找使用指定节点组的节点
            for node in material.node_tree.nodes:
                if (node.type == 'GROUP' and node.node_tree and 
                    node.node_tree.name == active_node_group and
                    'Select' in node.inputs):
                    
                    # 双向同步：如果节点值改变，更新全局属性
                    node_value = node.inputs['Select'].default_value
                    if node_value != expression_index:
                        # 添加日志输出，便于调试
                        print(f"Expression Switcher: 同步节点值 {node_value} 到全局属性 {expression_index}")
                        scene.global_node_group_settings.expression_index = int(node_value)
                        return  # 找到一个不匹配的就更新全局值并返回
    except Exception as e:
        # 错误处理，避免中断程序执行
        print(f"Expression Switcher - update_node_group_inputs 错误: {str(e)}")
        pass  # 静默处理错误，避免影响Blender正常运行

class NODE_OT_SET_KEYFRAME(Operator):
    """为当前表情索引设置关键帧"""
    bl_idname = "node.set_face_keyframe"
    bl_label = "设置关键帧"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        active_node_group = scene.global_node_group_settings.active_node_group
        
        if not active_node_group:
            self.report({'ERROR'}, "请先选择一个节点组")
            return {'CANCELLED'}
        
        # 给选中物体中使用该节点组的节点设置关键帧
        selected_nodes = get_selected_nodes_with_group(context, active_node_group)
        for node, obj in selected_nodes:
            if 'Select' in node.inputs:
                node.inputs['Select'].keyframe_insert(data_path="default_value")
        
        self.report({'INFO'}, f"已为 {active_node_group} 设置关键帧")
        return {'FINISHED'}

class NODE_OT_REMOVE_KEYFRAME(Operator):
    """为当前表情索引去除关键帧"""
    bl_idname = "node.remove_face_keyframe"
    bl_label = "去除关键帧"
    bl_options = {'REGISTER', 'UNDO'}
    
    def execute(self, context):
        scene = context.scene
        active_node_group = scene.global_node_group_settings.active_node_group
        
        if not active_node_group:
            self.report({'ERROR'}, "请先选择一个节点组")
            return {'CANCELLED'}
        
        # 给选中物体中使用该节点组的节点去除关键帧
        selected_nodes = get_selected_nodes_with_group(context, active_node_group)
        for node, obj in selected_nodes:
            if 'Select' in node.inputs:
                node.inputs['Select'].keyframe_delete(data_path="default_value")
        
        # 强制刷新UI，特别是时间轴区域
        self.refresh_timeline_ui(context)
        
        self.report({'INFO'}, f"已为 {active_node_group}组 去除关键帧")
        return {'FINISHED'}
    
    def refresh_timeline_ui(self, context):
        """强制刷新时间轴UI"""
        # 刷新所有区域
        for area in context.screen.areas:
            # 刷新时间轴区域
            if area.type == 'TIMELINE':
                area.tag_redraw()
            # 刷新动画编辑器区域
            elif area.type in ('DOPESHEET_EDITOR', 'GRAPH_EDITOR'):
                area.tag_redraw()
        
        # 强制更新UI
        context.area.tag_redraw()
        bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1)

def update_active_node_group_index(self, context):
    """当节点组列表的激活索引改变时自动设置活动节点组"""
    scene = context.scene
    # 获取实际的索引值，而不是使用self（Scene对象）
    index = scene.face_change_active_node_group_index
    if (scene.face_change_node_groups and 
        index >= 0 and 
        index < len(scene.face_change_node_groups)):
        
        active_item = scene.face_change_node_groups[index]
        current_active = scene.global_node_group_settings.active_node_group
        
        # 如果点击的是当前激活的节点组，则取消激活
        if active_item.name == current_active:
            scene.global_node_group_settings.active_node_group = ""
        else:
            scene.global_node_group_settings.active_node_group = active_item.name


# 新增：删除未使用节点组的操作符
class NODE_OT_DELETE_UNUSED_GROUP(Operator):
    """删除选定的未使用节点组"""
    bl_idname = "node.delete_unused_group"
    bl_label = "删除节点组"
    bl_options = {'REGISTER', 'UNDO'}

    @classmethod
    def poll(cls, context):
        scene = context.scene
        index = scene.face_change_active_node_group_index
        if (scene.face_change_node_groups and 
            index >= 0 and 
            index < len(scene.face_change_node_groups)):
            item = scene.face_change_node_groups[index]
            for met in bpy.data.materials:
                if item.name in met.node_tree.nodes:
                    return False
        return True
    
    def execute(self, context):
        scene = context.scene
        index = scene.face_change_active_node_group_index
        
        if (not scene.face_change_node_groups or 
            index < 0 or 
            index >= len(scene.face_change_node_groups)):
            self.report({'ERROR'}, "未选择有效的节点组")
            return {'CANCELLED'}
        
        item = scene.face_change_node_groups[index]

        # 从Blender数据中删除节点组
        node_group = bpy.data.node_groups.get(item.name)
        if node_group:
            bpy.data.node_groups.remove(node_group)
            self.report({'INFO'}, f"已删除节点组: {item.name}")
        else:
            self.report({'WARNING'}, f"未找到节点组: {item.name}")
        
        # 刷新节点组列表
        bpy.ops.node.refresh_node_groups()
        
        return {'FINISHED'}
    
    def invoke(self, context, event):
        return context.window_manager.invoke_confirm(self, event)

class MATERIAL_PT_FACE_CHANGE(Panel):
    bl_label = "群组表情切换"
    bl_idname = "MATERIAL_PT_FACE_CHANGE"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "material"
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        
        box = layout.box()
        box.label(text="可用节点组:")
        
        row = box.row()
        row.template_list(
            "NODE_UL_NODE_GROUPS", 
            "Node Groups", 
            scene, 
            "face_change_node_groups", 
            scene, 
            "face_change_active_node_group_index",
            rows=4
        )
        col = row.column(align=True)
        # 刷新按钮
        col.operator("node.create_face_change_group", icon='ADD',text="")
        col.operator("node.refresh_node_groups", icon='FILE_REFRESH',text="")
        
        # 获取当前选中的节点组项
        index = scene.face_change_active_node_group_index
        if index >= 0 and index < len(scene.face_change_node_groups):
            item = scene.face_change_node_groups[index]
            
            active_node_group = scene.global_node_group_settings.active_node_group
            
            # 查找当前活动节点组的详细信息
            active_item = None
            for item in scene.face_change_node_groups:
                if item.name == active_node_group:
                    active_item = item
                    break
            
            
            is_used=False
            if active_item:
                # 显示使用该节点组的材质数量
                material_count = 0
                for material in bpy.data.materials:
                    if material.use_nodes and material.node_tree:
                        for node in material.node_tree.nodes:
                            if (node.type == 'GROUP' and node.node_tree and 
                                node.node_tree.name == active_item.name):
                                material_count += 1
                                break
                
                # 判断节点是否使用
                is_used = material_count > 0
                col2 = box.column()
                # 对于未使用的节点组，显示删除按钮
                if not is_used:
                    col.operator("node.delete_unused_group", icon='TRASH', text="")
                    col2.label(text="状态: 未被使用", icon='ERROR')
                else:
                    # 显示关键帧设置按钮
                    col.operator("node.set_face_keyframe", icon='KEY_HLT', text="")
                    col.operator("node.remove_face_keyframe", icon='KEY_DEHLT', text="")
                    # 使用split布局来更好地控制标签和滑块的位置
                    split = col2.split(factor=0.3, align=True)
                    split.label(text="表情索引:")
                    # 右侧部分再分割为滑块和数字显示
                    row_right = split.row(align=True)
                    row_right.prop(scene.global_node_group_settings, "expression_index", text="")
                    # 显示当前节点组信息
                    col2.label(text=f"节点组: {active_item.name}")
                    col2.label(text=f"表情数量: {active_item.expression_count}")
                    # 显示选中物体数量
                    selected_nodes = get_selected_nodes_with_group(context, active_node_group)
                    col2.label(text=f"选中物体中的节点: {len(selected_nodes)}")
                    col2.label(text="状态: 已被使用", icon='CHECKMARK')
                    col2.label(text=f"使用该节点组的材质: {material_count}")
            
        else:
            # 显示没有活动节点组的提示
            box.label(text="没有活动节点组", icon='INFO')



node_group_classes = (
    UVMapItem,
    NodeGroupItem,
    GlobalNodeGroupSettings,
    NODE_UL_UV_MAPS,
    NODE_UL_NODE_GROUPS,
    NODE_OT_REFRESH_UV_MAPS,
    NODE_OT_REFRESH_NODE_GROUPS,
    NODE_OT_CREATE_FACE_CHANGE_GROUP,
    NODE_OT_SET_KEYFRAME,
    NODE_OT_REMOVE_KEYFRAME,
    NODE_OT_DELETE_UNUSED_GROUP,
    MATERIAL_PT_FACE_CHANGE,
)

# 注册场景更新前的处理函数
@bpy.app.handlers.persistent
def scene_update_pre_handler(scene):
    update_node_group_inputs(scene)

def node_group_register():
    for cls in node_group_classes:
        bpy.utils.register_class(cls)
    
    # 注册场景属性
    bpy.types.Scene.face_change_uv_maps = CollectionProperty(type=UVMapItem)
    bpy.types.Scene.face_change_active_uv_map_index = IntProperty(default=0)
    bpy.types.Scene.face_change_node_groups = CollectionProperty(type=NodeGroupItem)
    bpy.types.Scene.face_change_active_node_group_index = IntProperty(
        default=0,
        update=update_active_node_group_index
    )
    bpy.types.Scene.global_node_group_settings = bpy.props.PointerProperty(type=GlobalNodeGroupSettings)
    
    # 添加场景更新前的处理函数
    if scene_update_pre_handler not in bpy.app.handlers.depsgraph_update_pre:
        bpy.app.handlers.depsgraph_update_pre.append(scene_update_pre_handler)

def node_group_unregister():
    for cls in reversed(node_group_classes):
        bpy.utils.unregister_class(cls)
        
    # 删除场景属性
    del bpy.types.Scene.face_change_uv_maps
    del bpy.types.Scene.face_change_active_uv_map_index
    del bpy.types.Scene.face_change_node_groups
    del bpy.types.Scene.face_change_active_node_group_index
    del bpy.types.Scene.global_node_group_settings
    
    # 移除 handler
    if scene_update_pre_handler in bpy.app.handlers.depsgraph_update_pre:
        bpy.app.handlers.depsgraph_update_pre.remove(scene_update_pre_handler)